#include "BondDict.h"

#include <algorithm>
#include <fstream>

//////////////////////////////////////////////////////////////////////
// class CBondDict

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
char BondDict::Empty = 0;

BondDict::BondDict() {
  selective_code[0] = 0;
  sortcode[0] = 0;
  group_name[0] = 0;
  group_name_original[0] = 0;
  selective_code_original[0] = 0;
  selective_content = &BondDict::Empty;
  selective_content_en = &BondDict::Empty;
}

BondDict::BondDict(const BondDict& rhs) {
  memcpy(selective_code, rhs.selective_code, sizeof(selective_code));
  memcpy(sortcode, rhs.sortcode, sizeof(sortcode));
  memcpy(group_name, rhs.group_name, sizeof(group_name));
  memcpy(group_name_original, rhs.group_name_original,
         sizeof(group_name_original));
  memcpy(selective_code_original, rhs.selective_code_original,
         sizeof(selective_code_original));

  selective_content = &BondDict::Empty;
  selective_content_en = &BondDict::Empty;
  SetSelectiveContent(rhs.selective_content);
  SetSelectiveContentEn(rhs.selective_content_en);
}

BondDict::~BondDict() {
  if (selective_content && selective_content != &BondDict::Empty) {
    free(selective_content);
  }
  if (selective_content_en && selective_content_en != &BondDict::Empty) {
    free(selective_content_en);
  }
}

BondDict& BondDict::operator=(const BondDict& rhs) {
  memcpy(selective_code, rhs.selective_code, sizeof(selective_code));
  memcpy(sortcode, rhs.sortcode, sizeof(sortcode));
  memcpy(group_name, rhs.group_name, sizeof(group_name));
  memcpy(group_name_original, rhs.group_name_original,
         sizeof(group_name_original));
  memcpy(selective_code_original, rhs.selective_code_original,
         sizeof(selective_code_original));

  SetSelectiveContent(rhs.selective_content);
  SetSelectiveContentEn(rhs.selective_content_en);
  return *this;
}

void BondDict::SetSelectiveContent(const char* content) {
  if (selective_content == content) return;
  if (selective_content != &BondDict::Empty && selective_content != nullptr) {
    free(selective_content);
  }
  if (content == nullptr || content[0] == 0) {
    selective_content = &BondDict::Empty;
  } else {
    selective_content = (char*)malloc(strlen(content) + 1);
    strcpy(selective_content, content);
  }
}

void BondDict::SetSelectiveContentEn(const char* content) {
  if (selective_content_en == content) return;
  if (selective_content_en != &BondDict::Empty &&
      selective_content_en != nullptr) {
    free(selective_content_en);
  }
  if (content == nullptr || content[0] == 0) {
    selective_content_en = &BondDict::Empty;
  } else {
    selective_content_en = (char*)malloc(strlen(content) + 1);
    strcpy(selective_content_en, content);
  }
}

CBondDict::CBondDict() {}

CBondDict::~CBondDict() { Clear(); }

bool CBondDict::Add(BondDict& dict) {
  std::string sgroup = dict.group_name;
  if (sgroup.length() <= 0) return false;
  std::lock_guard<std::mutex> locker(m_mutex);
  CBondList* parr = nullptr;
  parr = GetBondArrByGroup(sgroup, true);
  if (!parr) return false;
  std::string skey = sgroup + "." + std::string(dict.selective_code);
  parr->m_list.insert(std::pair<std::string, BondDict>(skey, dict));
  return true;
}

int CBondDict::GetSize() {
  int res = 0;
  for (std::map<std::string, CBondList*>::iterator it = m_map.begin();
       it != m_map.end(); ++it) {
    res += (int)it->second->m_list.size();
  }

  return res;
}

CBondDict& CBondDict::instance() {
  static CBondDict s_bd;
  return s_bd;
}

CBondList* CBondDict::GetBondArrByGroup(const std::string& sGroup,
                                        bool bInsert) {
  CBondList* parr = nullptr;
  std::string sGroupLow = sGroup;
  transform(sGroupLow.begin(), sGroupLow.end(), sGroupLow.begin(), tolower);
  std::map<std::string, CBondList*>::iterator itr = m_map.find(sGroupLow);
  if (itr != m_map.end())
    parr = itr->second;
  else if (bInsert) {
    parr = new CBondList;
    m_map.insert(std::pair<std::string, CBondList*>(sGroup, parr));
  }
  return parr;
}

bool CBondDict::GetBondDict(const char* sGroup, const char* sCode,
                            BondDict& stDict) {
  if (sGroup == nullptr || sCode == nullptr) return false;
  if (strlen(sGroup) == 0 || strlen(sCode) == 0) return false;

  std::string sGroupLow = sGroup, sCodeLow = sCode;
  transform(sGroupLow.begin(), sGroupLow.end(), sGroupLow.begin(), tolower);
  transform(sCodeLow.begin(), sCodeLow.end(), sCodeLow.begin(), tolower);

  std::lock_guard<std::mutex> locker(m_mutex);

  CBondList* parr = nullptr;
  parr = GetBondArrByGroup(sGroupLow);
  if (parr) {
    std::string strMapKey =
        std::string(sGroupLow) + "." + std::string(sCodeLow);
    std::map<std::string, BondDict>::iterator itr =
        parr->m_list.find(strMapKey);
    if (itr != parr->m_list.end()) {
      stDict = itr->second;
      return true;
    }
  }

  return false;
}

bool CBondDict::Clear() {
  std::lock_guard<std::mutex> locker(m_mutex);

  std::map<std::string, CBondList*>::iterator itr = m_map.begin();
  for (itr = m_map.begin(); itr != m_map.end(); itr++) {
    CBondList* parr = itr->second;
    if (parr) delete parr;
    parr = nullptr;
  }
  m_map.clear();

  return true;
}

void CBondDict::DumpStatus(int mode) const {}